// Final7542.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <map>
#include <list>
#include "math.h"

using namespace std;

#define anchoAjedrez 32
#define altoAjedrez 32

class Jugador {
private:
	string nombre;
	unsigned int puntaje;

public:
	Jugador::Jugador (string nombre, unsigned int puntaje) {
		this->nombre = nombre;
		this->puntaje = puntaje;
	}

	string Jugador::getNombre () {
		return this->nombre;
	}

	unsigned int Jugador::getPuntaje () {
		return this->puntaje;
	}

	void Jugador::setPuntaje (unsigned int puntaje) {
		this->puntaje = puntaje;
	}
};

class FileBadException: public exception {
private:
	string mensaje;
public:
	FileBadException(string msje) {
		this->mensaje = msje;
	}

	~FileBadException() throw () {
	}

	const char* what() const throw () {
		return mensaje.c_str();
	}
};

class BmpHandler {

/* 
 * ---------------------------------------------------------------------------------------------
 *            | shift (hex) |         Name         | Size(Bytes) |  Content (Description)
 *   BitMap   |    0000h    | Identifier (ID)      |      2      |        'BM'
 *   File     |    0002h    | File Size            |      4      |
 *   Header   |    0006h    | Reserved             |      4      |
 * (14 Bytes) |    000Ah    | Bitmap Data Offset   |      4      |
 * ---------------------------------------------------------------------------------------------
 *            |    000Eh    | Bitmap Header Size   |      4      |
 *            |    0012h    | Width                |      4      | Ancho (en pixeles)
 *            |    0016h    | Height               |      4      | Alto (en pixeles)
 *   BitMap   |    001Ah    | Planes               |      2      |
 *   Info     |    001Ch    | Bits Per Pixel       |      2      | 8bpp;16bpp;24bpp;32bpp
 *   Header   |    001Eh    | Compression          |      4      | 0 : Sin comprimir
 * (40 Bytes  |    0022h    | Bitmap Data Size     |      4      |
 *            |    0026h    | H-Resolution         |      4      | (Pixel/Meter)
 *            |    002Ah    | V-Resolution         |      4      | (Pixel/Meter)
 *            |    002Eh    | Used Colors          |      4      | 0 : None
 *            |    0032h    | Important Colors     |      4      | 0 : All colors are important
 *----------------------------------------------------------------------------------------------
 *   BitMap   |    0036h    |        BitMap        |      -      | Desde Izq-Abajo 
 *   Array    |    -----    |        Data          |      -      | hacia Der-Arriba
 *----------------------------------------------------------------------------------------------
 *
 *								24Bit Bitmap (RGB: 8,8,8)
 * Red   : 00 00 FF : (0,0,255)            White : FF FF FF : (255,255,255)
 * Green : 00 FF 00 : (0,255,0)            Black : 00 00 00 : (0,0,0)
 * Blue  : FF 00 00 : (255,0,0)
 *
 * Formula de Desplazamiento:
 *
 *		Posicion = Dir.Inicio + Desplazamiento
 *
 *		Desplazamiento = Col * L + Fil * L * Cant.Col.
 */


private:

	char* Buffer4Bytes;
	char* Buffer3Bytes;
	char* Buffer2Bytes;

public:

BmpHandler::BmpHandler() {
	this->Buffer4Bytes = new char [4];
	this->Buffer3Bytes = new char [3];
	this->Buffer2Bytes = new char [2];
}

BmpHandler::~BmpHandler() {
	delete this->Buffer4Bytes;
	delete this->Buffer3Bytes;
	delete this->Buffer2Bytes;
}
	
char* BmpHandler::getBuffer2Bytes() {
	return this->Buffer2Bytes;
}

char* BmpHandler::getBuffer3Bytes() {
	return this->Buffer3Bytes;
}

char* BmpHandler::getBuffer4Bytes() {
	return this->Buffer4Bytes;
}

char* BmpHandler::escribir2Bytes(unsigned int numero) {

	memcpy(this->Buffer2Bytes, &numero, 2);
	return this->Buffer2Bytes;
}

char* BmpHandler::escribir3Bytes(unsigned int numero) {

	memcpy(this->Buffer3Bytes, &numero, 3);
	return this->Buffer3Bytes;
}

char* BmpHandler::escribir4Bytes(unsigned int numero) {

	memcpy(this->Buffer4Bytes, &numero, sizeof(unsigned int));
	return this->Buffer4Bytes;
}

unsigned int BmpHandler::leer2Bytes(fstream* bmp) {

	unsigned int byte1 = bmp->get();
	unsigned int byte2 = bmp->get();

	return byte1 + byte2 * 256;
}

unsigned int BmpHandler::leer3Bytes (fstream* bmp) {
	unsigned int byte1 = bmp->get();
	unsigned int byte2 = bmp->get();
	unsigned int byte3 = bmp->get();

	return byte1 + byte2 * 256 + byte3 * 256 * 256;
}

unsigned int BmpHandler::leer4Bytes(fstream* bmp) {

	unsigned int byte1 = bmp->get();
	unsigned int byte2 = bmp->get();
	unsigned int byte3 = bmp->get();
	unsigned int byte4 = bmp->get();

	return byte1 + byte2 * 256 + byte3 * 256 * 256 + byte4 * 256 * 256 * 256;
}

void BmpHandler::getInformacion(string path) {
	fstream bmp;
	bmp.open(path.c_str(), ios::in | ios::out | ios::binary);
	if (!bmp.good()) {
		throw FileBadException("Error al abrir el archivo de bmp");
	}
	cout << "El archivo: " << path << endl;
	unsigned int IdBmp;
	unsigned int tamBmp;
	IdBmp = this->leer2Bytes(&bmp);
	this->escribir2Bytes(IdBmp);
	cout << "El identificador: " << this->getBuffer2Bytes() << endl;
	tamBmp = this->leer4Bytes(&bmp);
	cout << "Tamanio de la imagen: " << tamBmp << " Bytes" << endl;
	this->leer4Bytes(&bmp);
	unsigned int tamCabecera = this->leer4Bytes(&bmp);
	cout << "Tamanio de la cabecera: " << tamCabecera << " Bytes" << endl;
	this->leer4Bytes(&bmp);
	unsigned int ancho = this->leer4Bytes(&bmp);
	cout << "Ancho de la imagen: " << ancho << " en Pixeles" << endl;
	unsigned int alto = this->leer4Bytes(&bmp);
	cout << "Alto de la imagen: " << alto << " en Pixeles" << endl;
	this->leer2Bytes(&bmp);
	unsigned int bpp = this->leer2Bytes(&bmp);
	cout << "Bits por Pixel: " << bpp << endl;
	unsigned int comp = this->leer4Bytes(&bmp);
	if (comp == 0) {
		cout << "Compression: " << comp << " (Sin comprimir)" << endl;
	}
	unsigned int tamDatos = this->leer4Bytes(&bmp);
	cout << "Tamanio de datos: " << tamDatos << " en Bytes" << endl;
	unsigned int Hres = this->leer4Bytes(&bmp);
	cout << "Horizontal Resolution: " << Hres << " Pixel/Meter" << endl;
	unsigned int Vres = this->leer4Bytes(&bmp);
	cout << "Vertical Resolution: " << Vres << " Pixel/Meter" << endl;
	unsigned int usedColors = this->leer4Bytes(&bmp);
	cout << "Used colors: " << usedColors << " (0: None)" << endl;
	unsigned int impColors = this->leer4Bytes(&bmp);
	cout << "Important colors: " << impColors
			<< " (0: All colors are important)" << endl;
}

};

void resize(string pathOrig, int nuevoAncho, int nuevoAlto, string pathDest) {
	unsigned int tamCabecera, ancho, alto, tamArch;
	bool esBmp = false;
	FILE* bmp;//bmp a redimensionar
	FILE* bmpDest;//bmp redimensionado
	// Abro los dos archivos, uno para leer y otro para escribir
	bmp = fopen (pathOrig.c_str(), "rb");
	
	if (pathDest == "") {
		pathDest = "bmpTemp";
	}

	bmpDest = fopen (pathDest.c_str(), "wb");
	
	// Verifico si el archivo cumple el formato de un bmp
	if ( fgetc(bmp) == 'B' && fgetc(bmp) == 'M') {
		esBmp = true;
	}
	if (esBmp) {
		// Cargo los datos importantes del bmp original
		fread (&tamArch, 4, 1, bmp);
		fseek (bmp, 10, SEEK_SET);
		fread (&tamCabecera, 4, 1, bmp);
		fseek (bmp, 18, SEEK_SET);
		fread (&ancho, 4, 1, bmp);
		fread (&alto, 4, 1, bmp);

		// Cargo la cabecera del bmp original en la memoria
		// y luego copio al bmp destino
		char* cabecera = new char[tamCabecera];
		fseek (bmp, 0, SEEK_SET);
		fread (cabecera, tamCabecera, 1, bmp);
		fwrite (cabecera, tamCabecera, 1, bmpDest);

		// Calculo las escalas
		double escalaAncho = (double) ancho / (double) nuevoAncho;
		double escalaAlto = (double) alto / (double) nuevoAlto;

		// Cargo los datos de bmp original en memoria
		
		unsigned int cantBytesOrig = tamArch - tamCabecera - ((ancho % 4)
				* alto);
		char* bytesImagOrig = new char[cantBytesOrig];
		int contOrig = 0;
		for (int y = 0; y < alto; y++) {
			for (int x = 0; x < ancho; x++) {
				fread (&bytesImagOrig[contOrig], 1, 1, bmp);
				fread (&bytesImagOrig[contOrig+1], 1, 1, bmp);
				fread (&bytesImagOrig[contOrig+2], 1, 1, bmp);
				contOrig += 3;
			}
			// Cuando una fila no esta alineado a 4 bytes,
			// se le agregan los bytes de padding, por lo tanto los ignoro
			for (int p = 0; p < (ancho % 4); p++) {
				char aux;
				fread (&aux, 1, 1, bmp);
			}
		}

		// Modifico los datos de cabecera del bmp destino

		unsigned int cantBytesFinal = (nuevoAncho * nuevoAlto * 3)
				+ ((nuevoAncho % 4) * nuevoAlto);
		fseek (bmpDest, 2, SEEK_SET);
		int tamArchDest = tamCabecera + cantBytesFinal;
		fwrite (&tamArchDest, 4, 1, bmpDest);
		fseek (bmpDest, 18, SEEK_SET);
		fwrite (&nuevoAncho, 4, 1, bmpDest);
		fwrite (&nuevoAlto, 4, 1, bmpDest);
		fseek (bmpDest, 34, SEEK_SET);
		fwrite (&cantBytesFinal, 4, 1, bmpDest);
		fseek (bmpDest, tamCabecera, SEEK_SET);

		// Copio los pixeles del bmp original segun las
		// escalas calculadas aplicandole la transformacion,
		// luego grabo en el bmp destino
		int offset;
		int contador = 0;
		int pixels = 0;
		for (int y = 0; y < nuevoAlto; y++) {
			for (int x = 0; x < nuevoAncho; x++) {
				// Aca aplico la formula de desplazamiento
				int despX = escalaAncho * x;
				int despY = escalaAlto * y;
				offset = 0;
				pixels = ancho * despY + despX;
				offset += pixels * 3;

				fwrite (&bytesImagOrig[offset], 1, 1, bmpDest);
				fwrite (&bytesImagOrig[offset+1], 1, 1, bmpDest);
				fwrite (&bytesImagOrig[offset+2], 1, 1, bmpDest);
				
				contador += 3;
			}
			// Cuando una fila no esta alineado a 4 bytes,
			// le agrego los bytes de padding que faltan
			for (int p = 0; p < (nuevoAncho % 4); p++) {
				char aux = '0';
				fwrite (&aux, 1, 1, bmpDest);
			}
		}

		// Cierro los dos archivos
		fclose (bmp);
		fclose (bmpDest);
		
		if (pathDest == "bmpTemp") {
			remove(pathOrig.c_str());
			rename("bmpTemp", pathOrig.c_str());
		}
		// Libero los recursos
		delete[] bytesImagOrig;
		delete[] cabecera;

	}
}

void rotar3 (string path, string pathFinal) {
	FILE* bmp;
	bmp = fopen (path.c_str(), "rb");
	
	FILE* bmpDest;
	bmpDest = fopen (pathFinal.c_str(), "wb");

	unsigned int tamanioArch, ancho, alto, finCabecera;
	unsigned int nuevoAncho, nuevoAlto, tamContenido;

	fseek (bmp, 2, SEEK_SET);
	fread (&tamanioArch, 4, 1, bmp);
	fseek (bmp, 10, SEEK_SET);
	fread (&finCabecera, 4, 1, bmp);
	fseek (bmp, 18, SEEK_SET);
	fread (&ancho, 4, 1, bmp);
	fread (&alto, 4, 1, bmp);

    nuevoAncho = alto;
    nuevoAlto = ancho;
	tamContenido = tamanioArch - finCabecera;

	char* cabecera = new char [finCabecera];
	fseek (bmp, 0, SEEK_SET);
	fread (cabecera, finCabecera, 1, bmp);
	fwrite (cabecera, finCabecera, 1, bmpDest);

    char * contenidoOrg = new char[tamContenido];
    fseek(bmp, finCabecera, SEEK_SET);
    fread(contenidoOrg, tamContenido, 1, bmp);
        
	char * contenidoRot = new char[tamContenido + alto * 12];
    int x, y, posX, posY, offsetOrg, offsetRot, pixel;
    offsetRot = -3;
    char relleno = '0';

    for (x = 0; x < ancho; x++) {
		for (y = 0; y < alto; y++) {
            pixel = y * ancho + x;
            offsetOrg = pixel * 3;

            offsetRot += 3;
            memcpy(&contenidoRot[offsetRot], &contenidoOrg[offsetOrg], 3);
		}
        for (int c=0; c<alto%4;c++) {
            offsetRot++;
            memcpy(&contenidoRot[offsetRot], &relleno, 1);
        }
    }

	tamContenido = offsetRot;
	fwrite (contenidoRot, tamContenido, 1, bmpDest);

	fseek (bmpDest, 18, SEEK_SET);
	fwrite (&nuevoAncho, 4, 1, bmpDest);
	fwrite (&nuevoAlto, 4, 1, bmpDest);

    delete[] contenidoOrg;
	delete[] contenidoRot;

	fclose (bmp);
	fclose (bmpDest);
}

void rotar(string path, string pathFinal) {
	FILE* bmp;
	bmp = fopen (path.c_str(), "rb");
	
	int  inicio_datos, alto, ancho,tam_arch;
	FILE* bmpDest;
	bmpDest = fopen (pathFinal.c_str(), "wb");

	bool esBMP = false; 
	if (fgetc (bmp) == 'B' && fgetc(bmp) == 'M') {
		esBMP = true;
	}
	if (esBMP) {
		fread (&tam_arch, 4, 1, bmp);
		fseek (bmp, 10, SEEK_SET);
		fread (&inicio_datos, 4, 1, bmp);
		fseek (bmp, 18, SEEK_SET);
		fread (&ancho, 4, 1, bmp);
		fread (&alto, 4, 1, bmp); 

		char* cabecera = new char[inicio_datos];
		fseek (bmp, 0, SEEK_SET);
		fread (cabecera, inicio_datos, 1, bmp);
		fwrite (cabecera, inicio_datos, 1, bmpDest);


		unsigned int cantBytesOriginal = tam_arch - inicio_datos;
		char* bytesImagenOriginal = new char[cantBytesOriginal];
		int contadorOriginal = 0;
		
		int offset = 0;
		char relleno = '0';

		
		for ( int y = 0; y <alto; y++ ) { 
			for (  int x = 0; x < ancho; x++) { 
				fread (&bytesImagenOriginal[contadorOriginal], 1, 1, bmp);
				fread (&bytesImagenOriginal[contadorOriginal+1], 1, 1, bmp);
				fread (&bytesImagenOriginal[contadorOriginal+2], 1, 1, bmp);
				contadorOriginal +=3;
			}
			for ( int p = 0; p < (ancho % 4); p++) {
				char aux;
				fread (&aux, 1, 1, bmp);
			}
		}

		for ( int y = ancho ; y > 0 ; y-- ) { 
			offset = y;
			for ( int x = 0 ; x < alto ; x++) { 
				char B =  bytesImagenOriginal[offset*3];
				char G =  bytesImagenOriginal[offset*3+1];
				char R =  bytesImagenOriginal[offset*3+2];
		            
				fwrite (&B, 1, 1, bmpDest);
				fwrite (&G, 1, 1, bmpDest);
				fwrite (&R, 1, 1, bmpDest);
					            
				offset+=ancho;
			}
			for ( int p = 0 ; p < (alto % 4) ; p++) {
				fwrite (&relleno, 1, 1, bmpDest);
			}
		}

		fseek (bmpDest, 18, SEEK_SET);
		fwrite (&alto, 4, 1, bmpDest);
		fwrite (&ancho, 4, 1, bmpDest);

		delete[] cabecera;
		delete[] bytesImagenOriginal;
	}

	fclose (bmp);
	fclose (bmpDest);

}

void getRGB (unsigned int pixel, unsigned int& r, unsigned int& g, unsigned int& b) {
	r = pixel / (256 * 256);
	pixel -= r * (256 * 256);
	g = pixel / 256;
	pixel -= g * 256;
	b = pixel;
}

unsigned int getColor ( unsigned int r, unsigned int g, unsigned b ) {
	unsigned int result = 0;
	result += r * (256 * 256);
	result += g * 256;
	result += b;
	return result;
}

void mapAgregaColor (map<unsigned int, unsigned int> *listaColores, unsigned int colorValue) {
        map<unsigned int, unsigned int>::iterator itLista;
        itLista = listaColores->find(colorValue);

        if (itLista != listaColores->end())
        {
                itLista->second++;
        }else{
                listaColores->insert(pair<unsigned int, unsigned int>(colorValue, 1));
        }
}

unsigned int mapGetTransparente(map<unsigned int, unsigned int> listaColores) {
        unsigned int value;
        unsigned int max = 0;
        map<unsigned int, unsigned int>::iterator itLista;
        for (itLista = listaColores.begin(); itLista != listaColores.end(); itLista++)
        {
                unsigned int cant = itLista->second;
                if (max < cant)
                {
                        max = cant;
                        value = itLista->first;
				} else if ( max == cant) {
					unsigned int blanco = getColor (255, 255, 255);
					if ( labs (blanco - value) > labs (blanco - itLista->first) ) {
						max = cant;
						value = itLista->first;
					}
				}
        }
        return value;
}

unsigned int getColorTransparente(string pathOrig) {
	fstream bmp;
	bmp.open (pathOrig.c_str(), fstream::in, fstream::binary);
	if (!bmp.good()) {
		throw FileBadException ("Error al abrir archivo");
	}
	unsigned int ancho;
	unsigned int alto;
	BmpHandler* bmpHandler = new BmpHandler ();
	bmp.seekg (18, ios::beg);
	ancho = bmpHandler->leer4Bytes (&bmp);
	alto = bmpHandler->leer4Bytes (&bmp);
	map<unsigned int, unsigned int>* hashColores = new map<unsigned int, unsigned int>();
	bmp.seekg (54, ios::beg);
	for (unsigned int y = 0 ; y < alto ; y++) {
		for (unsigned int x = 0 ; x < ancho ; x++) {
			unsigned int color = bmpHandler->leer3Bytes (&bmp);
			mapAgregaColor (hashColores, color);
		}
		for (unsigned int p = 0 ; p < (ancho % 4) ; p++) {
			bmp.get();
		}
	}
	unsigned int resultado = mapGetTransparente (*hashColores);
	delete bmpHandler;
	delete hashColores;
	bmp.close ();
	return resultado;
}

bool esPar (unsigned int num) {
	return (num % 2 == 0);
}

unsigned int getColorAjedrez (unsigned int x, unsigned int y) {
	unsigned int coordX = x / anchoAjedrez;
	unsigned int coordY = y / altoAjedrez;
	unsigned int color;
	if ( esPar(coordX) ) {
		if ( esPar (coordY) ) {
			color = 0; // Color negro
		} else {
			color = getColor (255, 255, 255);
		}
	} else {
		if ( esPar (coordY) ) {
			color = getColor (255, 255, 255);
		} else {
			color = 0;
		}
	}
	return color;
}

void ponerFondoAjedrez (string pathOrigen, unsigned int colorTrasp ,string pathDestino) {
	fstream bmpOrigen;
	fstream bmpDestino;
	BmpHandler* bmpHandler = new BmpHandler();
	bool esBmp = false;
	bmpOrigen.open (pathOrigen.c_str(), fstream::in, fstream::binary );
	bmpDestino.open (pathDestino.c_str(), fstream::out, fstream::binary );
	if ( !bmpOrigen.good() ) {
		throw FileBadException ("Error al abrir archivo");
	}
	// Verifico si el archivo cumple el formato de un bmp
	if (bmpOrigen.get() == 'B' && bmpOrigen.get() == 'M') {
		esBmp = true;
	}
	if (esBmp) {
		unsigned int tamCabecera;
		unsigned int tamArch;
		unsigned int ancho;
		unsigned int alto;
		// Cargo los datos importantes del bmp original
		tamArch = bmpHandler->leer4Bytes(&bmpOrigen);
		bmpHandler->leer4Bytes(&bmpOrigen);
		tamCabecera = bmpHandler->leer4Bytes(&bmpOrigen);
		bmpHandler->leer4Bytes(&bmpOrigen);
		ancho = bmpHandler->leer4Bytes(&bmpOrigen);
		alto = bmpHandler->leer4Bytes(&bmpOrigen);
		bmpOrigen.seekg (0, ios::beg);
		for (unsigned int i = 0 ; i < tamCabecera ; i++) {
			bmpDestino.put (bmpOrigen.get());
		}
		unsigned int color;
		for (unsigned int y = 0 ; y < alto ; y++) {
			for (unsigned int x = 0 ; x < ancho ; x++) {
				// Me fijo si es un color transparente
				color = bmpHandler->leer3Bytes(&bmpOrigen);
				if (color == colorTrasp) {
					// Es un color transparente
					color = getColorAjedrez(x,y);
					bmpDestino.write (bmpHandler->escribir3Bytes (color), 3);
				} else {
					// No es un color transparente, entonces copio en destino
					bmpDestino.write (bmpHandler->escribir3Bytes (color), 3);
				}
			}
			for (unsigned int p = 0 ; p < (ancho % 2) ; p++) {
				bmpOrigen.get();
				char aux = '0';
				bmpDestino.write (&aux, sizeof (char));
			}
		}
	}

	bmpOrigen.close();
	bmpDestino.close();
	delete bmpHandler;
}

string getCadena (string pathArch, char delimit) {
	fstream archTxt;
	char c;
	string res;
	archTxt.open (pathArch.c_str(), fstream::in);
	while ( !archTxt.eof() ) {
		c = archTxt.get();
		if ( c != ' ' && c != '\n' && c != delimit) {
			res += c;
		}
		if ( c == delimit || c == '\n') {
			res += ' ';
		}
	}

	archTxt.close ();
	return res;
}

bool enRango (unsigned int x, unsigned int y, unsigned int ancho, unsigned int alto) {
	if ( x >= 0 && x <= ancho-1 && y >= 0 && y <= alto-1 ) {
		return true;
	} else {
		return false;
	}
}

unsigned int getPosicion (unsigned int x, unsigned int y, unsigned int ancho) {
	return ( x + ( y * ancho ) );
}

void printImagen (unsigned int* vector, unsigned int ancho, unsigned int alto) {
	cout << "--- Mostrando imagen ---" << endl;
	unsigned int cont = 0;
	unsigned int r,g,b;
	for (unsigned int y = 0 ; y < alto ; y++) {
		for (unsigned int x = 0 ; x < ancho ; x++) {
			cout << vector[cont];
			getRGB (vector[cont], r, g, b);
			cout << " (" << r << ",";
			cout << g << ",";
			cout << b << ") ";
			cont++;
		}
		cout << endl;
	}
}

void rellenar (unsigned int* arrayImag, unsigned int x, unsigned int y, unsigned int ancho, 
			   unsigned int alto, unsigned int color) {
	if ( enRango (x, y, ancho, alto) ) {
		unsigned int pos = getPosicion (x, y, ancho);
		arrayImag[pos] = color;
	}
}

void rellenar (unsigned int* arrayImag, unsigned int x, unsigned int y, 
			   unsigned int colorOrig, unsigned int colorDest, unsigned int ancho, unsigned int alto) {
	if ( enRango (x, y, ancho, alto) ) {
		unsigned int pos = getPosicion (x, y, ancho);
		if ( arrayImag[pos] == colorOrig ) {
			arrayImag[pos] = colorDest;
			// Diagonal superior izquierda
			//rellenar (arrayImag, x-1, y+1, colorOrig, colorDest, ancho, alto);
			// Diagonal superior derecha
			//rellenar (arrayImag, x+1, y+1, colorOrig, colorDest, ancho, alto);
			// Arriba
			rellenar (arrayImag, x, y+1, colorOrig, colorDest, ancho, alto);
			// Izquierda
			rellenar (arrayImag, x-1, y, colorOrig, colorDest, ancho, alto);
			// Derecha
			rellenar (arrayImag, x+1, y, colorOrig, colorDest, ancho, alto);
			// Diagonal inferior izquierda
			//rellenar (arrayImag, x-1, y-1, colorOrig, colorDest, ancho, alto);
			// Abajo
			rellenar (arrayImag, x, y-1, colorOrig, colorDest, ancho, alto);
			// Diagonal inferior derecha
			//rellenar (arrayImag, x+1, y-1, colorOrig, colorDest, ancho, alto);
		}
	}
}

void blanquearImagen (unsigned int* arreglo, unsigned int ancho, unsigned int alto) {

	unsigned int color = getColor(255,255,255);
	for (unsigned int y = 0 ; y < alto ; y++) {
		for (unsigned int x = 0 ; x < ancho ; x++) {
			rellenar (arreglo, x, y, ancho, alto, color);
		}
	}
}

void recortar (unsigned int* vectorOrig, unsigned int anchoOrig, unsigned int altoOrig, 
			   unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int* vectorDest) {
	unsigned int nuevoAncho = (x2 - x1) + 1;
	unsigned int nuevoAlto = (y2 - y1) + 1;
	unsigned int cont = 0;
	unsigned int auxX1 = x1;
	unsigned int auxY1 = y1;
	for (unsigned int y = 0 ; y < nuevoAlto ; y++) {
		for (unsigned int x = 0 ; x < nuevoAncho ; x++) {
			unsigned int pos = getPosicion (auxX1, auxY1, anchoOrig);
			vectorDest[cont] = vectorOrig[pos];
			cont++;
			if (auxX1 < x2) {
				auxX1++;
			} else {
				auxX1 = x1;
			}
		}
		
		auxY1++;
	}
}

void recortar (string archOrig, unsigned int x1, unsigned y1, 
			   unsigned int x2, unsigned int y2, string archDest) {
	FILE* bmpOrig;
	FILE* bmpDest;
	bmpOrig = fopen (archOrig.c_str(), "rb");
	bmpDest = fopen (archDest.c_str(), "wb");
	bool esBmp = false;


	if ( fgetc (bmpOrig) == 'B' && fgetc (bmpOrig) == 'M') {
		esBmp = true;
	}

	if (esBmp) {

		unsigned int tamCabecera;
		unsigned int tamArch;
		unsigned int ancho;
		unsigned int alto;

		// Cargo los datos importantes del bmp original
		fread (&tamArch, 4, 1, bmpOrig);
		fseek(bmpOrig, 10, SEEK_SET);
		fread (&tamCabecera, 4, 1, bmpOrig);
		fseek (bmpOrig, 18, SEEK_SET);
		fread (&ancho, 4, 1, bmpOrig);
		fread (&alto, 4, 1, bmpOrig);

		// Copio la cabecera en el bmp destino
		char* cabecera = new char [tamCabecera];
		fseek (bmpOrig, 0, SEEK_SET);
		fread (cabecera, 54, 1, bmpOrig);
		fwrite (cabecera, tamCabecera, 1, bmpDest);

		// Cargo el pixel array en memoria
		unsigned int* pixeles = new unsigned int [ancho * alto];
		unsigned int color = 0;
		unsigned int cont = 0;
		for (unsigned int y = 0 ; y < alto ; y++) {
			for (unsigned int x = 0 ; x < ancho ; x++) {
				fread (&color, 3, 1, bmpOrig);
				pixeles[cont] = color;
				cont++;
			}
			for (unsigned int p = 0 ; p < (ancho % 2) ; p++) {
				char aux;
				fread (&aux, 1, 1, bmpOrig);
			}
		}


		unsigned int nuevoAncho = (x2 - x1) + 1;
		unsigned int nuevoAlto = (y2 - y1) + 1;
		unsigned int* vectorNuevo = new unsigned int [nuevoAncho * nuevoAlto];
		recortar (pixeles, ancho, alto, x1, y1, x2, y2, vectorNuevo);
		 
		// Grabo en el archivo bmpDestino
		cont = 0;
		for (unsigned int y = 0 ; y < nuevoAlto ; y++) {
			for (unsigned int x = 0 ; x < nuevoAncho ; x++) {
				color = vectorNuevo[cont];
				fwrite (&color, 3, 1, bmpDest);
				cont++;
			}
			for (unsigned int p = 0 ; p < (nuevoAncho % 4) ; p++) {
				char aux = '0';
				fwrite (&aux, 1, 1, bmpDest);
			}
		}

		fseek (bmpDest, 2, SEEK_SET);
		tamArch = (nuevoAncho * nuevoAlto * 3) + ((nuevoAncho % 4) * nuevoAlto) + 54;
		fwrite (&tamArch, 4, 1, bmpDest);
		fseek (bmpDest, 18, SEEK_SET);
		fwrite (&nuevoAncho, 4, 1, bmpDest);
		fwrite (&nuevoAlto, 4, 1, bmpDest);

		delete[] cabecera;
		delete[] pixeles;
		delete[] vectorNuevo;

	}

	fclose (bmpOrig);
	fclose (bmpDest);
}

void testRellenar (string bmpDestino, unsigned int componente) {

	FILE* bmpDest;
	bmpDest = fopen (bmpDestino.c_str(), "wb");
	unsigned int ancho = 4;
	unsigned int alto = 4;
	char aux;
	aux = 'B';
	fwrite(&aux, 1, 1, bmpDest);
	aux = 'M';
	fwrite(&aux, 1, 1, bmpDest);
	// Tamanio de bmp
	unsigned int nro = (ancho * alto * 3) + 54 + (ancho % 4);
	fwrite(&nro, 4, 1, bmpDest);
	// Campo Reservado
	nro = 0;
	fwrite(&nro, 4, 1, bmpDest);
	// Tamanio de cabecera
	nro = 54;
	fwrite(&nro, 4, 1, bmpDest);
	// Tamanio de header
	nro = 40;
	fwrite(&nro, 4, 1, bmpDest);
	// Ancho
	fwrite(&ancho, 4, 1, bmpDest);
	// Alto
	fwrite(&alto, 4, 1, bmpDest);
	// Planos
	nro = 0;
	fwrite(&nro, 2, 1, bmpDest);
	// Bits per pixel
	nro = 24;
	fwrite(&nro, 2, 1, bmpDest);
	// Compression
	nro = 0;
	fwrite(&nro, 4, 1, bmpDest);
	// Bitmap Data Size
	nro = (ancho * alto * 3) + (ancho % 4);
	fwrite(&nro, 4, 1, bmpDest);
	// H-Resolution
	nro = 0;
	fwrite(&nro, 4, 1, bmpDest);
	// V-Resolution
	nro = 0;
	fwrite(&nro, 4, 1, bmpDest);
	// Used Colors
	nro = 0;
	fwrite(&nro, 4, 1, bmpDest);
	// Important Colors
	nro = 0;
	fwrite(&nro, 4, 1, bmpDest);
	// Pixel Array
	unsigned int* vector = new unsigned int [ancho * alto];
	blanquearImagen (vector, ancho, alto);
	unsigned int color = getColor (componente, 0, 0);
	rellenar (vector, 0, 0, ancho, alto, color);
	rellenar (vector, 0, 1, ancho, alto, color);
	rellenar (vector, 0, 2, ancho, alto, color);
	rellenar (vector, 0, 3, ancho, alto, color);
	color = getColor (0,componente,0);
	rellenar (vector, 1, 0, ancho, alto, color);
	rellenar (vector, 1, 1, ancho, alto, color);
	rellenar (vector, 1, 2, ancho, alto, color);
	rellenar (vector, 1, 3, ancho, alto, color);
	color = getColor (0,0,componente);
	rellenar (vector, 2, 0, ancho, alto, color);
	rellenar (vector, 2, 1, ancho, alto, color);
	rellenar (vector, 2, 2, ancho, alto, color);
	rellenar (vector, 2, 3, ancho, alto, color);
	color = getColor (componente,componente,componente);
	rellenar (vector, 3, 0, ancho, alto, color);
	rellenar (vector, 3, 1, ancho, alto, color);
	rellenar (vector, 3, 2, ancho, alto, color);
	rellenar (vector, 3, 3, ancho, alto, color);

	printImagen (vector, ancho, alto);
	unsigned int cont = 0;
	for (unsigned int y = 0 ; y < alto ; y++) {
		for (unsigned int x = 0 ; x < ancho ; x++) {
			unsigned int color = vector[cont];
			fwrite (&color, 3, 1, bmpDest);
			cont++;
		}
		for (unsigned int p = 0 ; p < (ancho % 2) ; p++) {
			char aux = '0';
			fwrite(&aux, 1, 1, bmpDest);
		}
	}

	delete[] vector;
	fclose (bmpDest);
}

void procesarBmp (string bmpOrigen, string bmpDestino) {
	FILE* bmpOrig;
	FILE* bmpDest;
	bmpOrig = fopen (bmpOrigen.c_str(), "rb");
	bmpDest = fopen (bmpDestino.c_str(), "wb");
	bool esBmp = false;


	if ( fgetc (bmpOrig) == 'B' && fgetc (bmpOrig) == 'M') {
		esBmp = true;
	}

	if (esBmp) {

		unsigned int tamCabecera;
		unsigned int tamArch;
		unsigned int ancho;
		unsigned int alto;

		// Cargo los datos importantes del bmp original
		fread (&tamArch, 4, 1, bmpOrig);
		fseek(bmpOrig, 10, SEEK_SET);
		fread (&tamCabecera, 4, 1, bmpOrig);
		fseek (bmpOrig, 18, SEEK_SET);
		fread (&ancho, 4, 1, bmpOrig);
		fread (&alto, 4, 1, bmpOrig);

		// Copio la cabecera en el bmp destino
		char* cabecera = new char [tamCabecera];
		fseek (bmpOrig, 0, SEEK_SET);
		fread (cabecera, 54, 1, bmpOrig);
		fwrite (cabecera, tamCabecera, 1, bmpDest);

		// Cargo el pixel array en memoria
		unsigned int* pixeles = new unsigned int [ancho * alto];
		unsigned int color = 0;
		unsigned int cont = 0;
		for (unsigned int y = 0 ; y < alto ; y++) {
			for (unsigned int x = 0 ; x < ancho ; x++) {
				fread (&color, 3, 1, bmpOrig);
				pixeles[cont] = color;
				cont++;
			}
			for (unsigned int p = 0 ; p < (ancho % 4) ; p++) {
				char aux;
				fread (&aux, 1, 1, bmpOrig);
			}
		}


		/**
		 *	Aca empiezo el procesamiento del pixel array
		 **/
		 
		// Grabo en el archivo bmpDestino
		cont = 0;
		for (unsigned int y = 0 ; y < alto ; y++) {
			for (unsigned int x = 0 ; x < ancho ; x++) {
				color = pixeles[cont];
				fwrite (&color, 3, 1, bmpDest);
				cont++;
			}
			for (unsigned int p = 0 ; p < (ancho % 4) ; p++) {
				char aux = '0';
				fwrite (&aux, 1, 1, bmpDest);
			}
		}

		delete[] cabecera;
		delete[] pixeles;

	}

	fclose (bmpOrig);
	fclose (bmpDest);

}

void baldecito (string bmpOrigen, string archTxt, string bmpDestino) {
	FILE* bmpOrig;
	FILE* bmpDest;
	bmpOrig = fopen (bmpOrigen.c_str(), "rb");
	bmpDest = fopen (bmpDestino.c_str(), "wb");
	
	bool esBmp = false;

	if ( fgetc (bmpOrig) == 'B' && fgetc (bmpOrig) == 'M') {
		esBmp = true;
	}

	if (esBmp) {

		unsigned int tamCabecera;
		unsigned int tamArch;
		unsigned int ancho;
		unsigned int alto;

		// Cargo los datos importantes del bmp original
		fread (&tamArch, 4, 1, bmpOrig);
		fseek(bmpOrig, 10, SEEK_SET);
		fread (&tamCabecera, 4, 1, bmpOrig);
		fseek (bmpOrig, 18, SEEK_SET);
		fread (&ancho, 4, 1, bmpOrig);
		fread (&alto, 4, 1, bmpOrig);

		// Copio la cabecera en el bmp destino
		char* cabecera = new char [tamCabecera];
		fseek (bmpOrig, 0, SEEK_SET);
		fread (cabecera, 54, 1, bmpOrig);
		fwrite (cabecera, tamCabecera, 1, bmpDest);

		// Cargo el pixel array en memoria
		unsigned int* pixeles = new unsigned int [ancho * alto];
		unsigned int color = 0;
		unsigned int cont = 0;
		for (unsigned int y = 0 ; y < alto ; y++) {
			for (unsigned int x = 0 ; x < ancho ; x++) {
				fread (&color, 3, 1, bmpOrig);
				pixeles[cont] = color;
				cont++;
			}
			for (unsigned int p = 0 ; p < (ancho % 2) ; p++) {
				char aux;
				fread (&aux, 1, 1, bmpOrig);
			}
		}

		string cadena = getCadena (archTxt, ',');
		stringstream ss;
		string aux = "";
		ss << cadena;
		ss >> aux;
		while (aux != "") {
			unsigned int x = atoi (aux.c_str());
			cout << "X:= " << x << endl;
			ss >> aux;
			unsigned int y = atoi (aux.c_str());
			cout << "Y:= " << y << endl;
			ss >> aux;
			unsigned int red = atoi (aux.c_str());
			//cout << "Red:= " << red << endl;
			ss >> aux;
			unsigned int green = atoi (aux.c_str());
			//cout << "Green:= " << green << endl;
			ss >> aux;
			unsigned int blue = atoi (aux.c_str());
			//cout << "Blue:= " << blue << endl;
			aux = "";
			ss >> aux;
			unsigned int colorReemplazo = getColor (red, green, blue);
			cout << "Color es := " << colorReemplazo << endl;
			
			unsigned int colorOrig = pixeles [ x + ( y * ancho ) ];
			rellenar (pixeles, x, y, colorOrig, colorReemplazo, ancho, alto);

		}
		cout << cadena << endl;
		// Grabo en el archivo bmpDestino
		cont = 0;
		for (unsigned int y = 0 ; y < alto ; y++) {
			for (unsigned int x = 0 ; x < ancho ; x++) {
				color = pixeles[cont];
				fwrite (&color, 3, 1, bmpDest);
				cont++;
			}
			for (unsigned int p = 0 ; p < (ancho % 2) ; p++) {
				char aux = '0';
				fwrite (&aux, 1, 1, bmpDest);
			}
		}
		
		delete[] cabecera;
		delete[] pixeles;

	}

	fclose (bmpOrig);
	fclose (bmpDest);

}

// Ordenamiento descendiente segun el puntaje de los jugadores
bool compJugador (Jugador* jug1, Jugador* jug2) {
	if (jug1->getPuntaje () > jug2->getPuntaje() ) {
		return true;
	} else {
		return false;
	}
}

void testBaldecito () {
	baldecito ("Balde3.bmp", "lineas.txt", "SalidaBalde3.bmp");
}

void testOrdJugador () {
	list<Jugador*>* listaJugador = new list<Jugador*>();
	Jugador* jug1 = new Jugador ("Juan", 100);
	Jugador* jug2 = new Jugador ("Pedro", 50);
	Jugador* jug3 = new Jugador ("Agustin", 100);
	listaJugador->push_back (jug1);
	listaJugador->push_back (jug2);
	listaJugador->push_back (jug3);
	

	list<Jugador*>::iterator it;
	Jugador* aux;
	for (it=listaJugador->begin(); it!=listaJugador->end(); it++) {
		aux = *it;
		cout << "Nombre: " << aux->getNombre() << endl;
		cout << "Puntaje: " << aux->getPuntaje() << endl;

	}

	listaJugador->sort(compJugador);
	cout << endl;

	for (it=listaJugador->begin(); it!=listaJugador->end(); it++) {
		aux = *it;
		cout << "Nombre: " << aux->getNombre() << endl;
		cout << "Puntaje: " << aux->getPuntaje() << endl;

	}

	delete listaJugador;
}

int main(int argc, char* argv[]) {
	BmpHandler* bmpHandler = new BmpHandler();
	try {
		fstream bmp;
		bmp.open ("Face.bmp", fstream::in, fstream::binary);
		if (!bmp.good() ){
			throw FileBadException ("Error al abrir archivo");
		}
		unsigned int ancho;
		unsigned int alto;
		bmp.seekg (18, ios::beg);
		ancho = bmpHandler->leer4Bytes(&bmp);
		alto = bmpHandler->leer4Bytes(&bmp);
		bmp.close ();
		//ancho *= 2;
		//alto *= 2;
		//bmpHandler->getInformacion("Face.bmp");
		//bmpHandler->resize ("Face.bmp", ancho, alto, "testResize.bmp");
		unsigned int colorTrasp = getColorTransparente ("Test1.bmp");
		unsigned int red, green, blue;
		getRGB (colorTrasp, red, green, blue);
		cout << "Red: " << red << " Green: " << green << " Blue: " << blue << endl;
		//ponerFondoAjedrez("testResize.bmp", colorTrasp, "NroPadronAlumno.bmp");
		//bmpHandler->getInformacion ("NroPadronAlumno.bmp");
		//rotar ("Face.bmp", "FaceRotado.bmp");
		//bmpHandler->getInformacion ("Face.bmp");
		//cout << endl;
		//bmpHandler->getInformacion ("FaceRotado.bmp");

	} catch (exception& e) {
		cout << e.what() << endl;
	}
	/*string cadena = getCadena ("lineas.txt", ',');
	stringstream ss;
	string aux = "";
	ss << cadena;
	ss >> aux;
	while (aux != "") {
		unsigned int x = atoi (aux.c_str());
		cout << "X:= " << x << endl;
		ss >> aux;
		unsigned int y = atoi (aux.c_str());
		cout << "Y:= " << y << endl;
		ss >> aux;
		unsigned int red = atoi (aux.c_str());
		//cout << "Red:= " << red << endl;
		ss >> aux;
		unsigned int green = atoi (aux.c_str());
		//cout << "Green:= " << green << endl;
		ss >> aux;
		unsigned int blue = atoi (aux.c_str());
		//cout << "Blue:= " << blue << endl;
		aux = "";
		ss >> aux;
		unsigned int color = getColor (red, green, blue);
		cout << "Color es := " << color << endl;
	}
	cout << cadena << endl;*/
	
	//testBaldecito();
	//testOrdJugador();

	testRellenar ("testRellenar.bmp", 125);
	procesarBmp ("test.bmp", "procesarBmp1.bmp");
	recortar ("testRellenar.bmp", 0, 0, 3, 0, "testCut.bmp");
	resize ("testRellenar.bmp", 100, 100, "testResize.bmp");
	rotar ("testResize.bmp", "testRotar.bmp");
	rotar3 ("testResize.bmp", "testRotar3.bmp");
	//testBaldecito ();
	delete bmpHandler;

	system ("pause");
	return 0;
}